use life_manager::manager::{Event, History};
use prettytable::{cell, row, Table};
use structopt::StructOpt;

const SPECIAL_TASKS_NAME: &str = "special";
const SPECIAL_EVENTS_NAME: &str = "event";
const DAILY_TASKS_NAME: &str = "daily";

fn print_event_list(list: &[Event], title: &str) {
    println!("{title}:");
    let mut table = Table::new();
    table.add_row(row!["name", "point", "alias"]);
    for Event { name, point, alias } in list.iter() {
        table.add_row(row![name, point, alias.as_ref().unwrap_or(&String::new())]);
    }
    table.printstd();
}

fn print_history(history: &[History], mut count: i32) {
    if count == -1 {
        count = i32::MAX;
    }

    let mut table = Table::new();
    table.add_row(row!["name", "type", "point", "date"]);
    for History {
        date,
        name,
        point,
        event_type,
    } in history.iter().rev()
    {
        table.add_row(row![name, event_type, point, date]);
        count -= 1;
        if count < 0 {
            break;
        }
    }
    table.printstd();
}

#[derive(Debug, StructOpt)]
#[structopt(name = "life game", about = "life game command line manager", global_setting = structopt::clap::AppSettings::AllowNegativeNumbers)]
enum Command {
    #[structopt(about = "add task")]
    Add {
        #[structopt(long = "type", short = "t", default_value = SPECIAL_TASKS_NAME)]
        task_type: String,
        name: String,
        point: i32,
        #[structopt(long = "alias", short = "a")]
        alias: Option<String>,
    },
    #[structopt(about = "list exist task or event")]
    List { task_type: String },
    #[structopt(about = "play something")]
    Play { name: String },
    #[structopt(about = "use point")]
    Use { point: i32, desc: String },
    #[structopt(about = "show point")]
    Point,
    #[structopt(about = "history")]
    History {
        #[structopt(
            about = "history number, default is 10, print all history if count is -1",
            default_value = "10"
        )]
        count: i32,
    },
    #[structopt(about = "remove")]
    Rm { name: String },
    #[structopt(about = "luck draw, get random point 0-29")]
    LuckDraw,
}

fn main() {
    let cmd = Command::from_args();
    let mut manager = life_manager::Manager::new();

    use Command::*;
    match cmd {
        Add {
            task_type,
            name,
            point,
            alias,
        } => match task_type.as_str() {
            // todo: 如果别名或者名称已经存在了，报错
            SPECIAL_TASKS_NAME => manager.add_special_task(name, point, alias),
            SPECIAL_EVENTS_NAME => manager.add_special_event(name, point, alias),
            DAILY_TASKS_NAME => manager.add_daily_task(name, point, alias),
            _ => eprintln!("task type {task_type} not exist"),
        },
        List { task_type } => match task_type.as_str() {
            SPECIAL_TASKS_NAME => print_event_list(manager.get_special_tasks(), &task_type),
            SPECIAL_EVENTS_NAME => print_event_list(manager.get_special_events(), &task_type),
            DAILY_TASKS_NAME => print_event_list(manager.get_daily_tasks(), &task_type),
            "all" => {
                print_event_list(manager.get_daily_tasks(), DAILY_TASKS_NAME);
                print_event_list(manager.get_special_tasks(), SPECIAL_TASKS_NAME);
                print_event_list(manager.get_special_events(), SPECIAL_EVENTS_NAME);
            }
            _ => panic!("task type {task_type} not exist"),
        },
        Play { name } => {
            if let Some(point) = manager.play(&name) {
                println!("new point is {point}")
            } else {
                eprintln!("no event or task named {name}")
            }
        }
        Use { point, desc } => {
            let new_point = manager.use_point_with_descript(point, desc);
            println!("use point {point}, new point is {new_point}")
        }
        Point => {
            println!("current point is {}", manager.point())
        }
        History { count } => print_history(manager.get_history(), count),
        Rm { name } => {
            if let Some(event) = manager.remove(&name) {
                println!("remove event: {}, point: {}", event.name, event.point)
            } else {
                println!("sorry, can't find event {}", name)
            }
        }
        LuckDraw => {
            let point = manager.luck_draw();
            println!("new point is {point}")
        }
    }
}
